using System;
using System.Collections.Generic;
using System.Text;

namespace NBear.Data
{
    public abstract class BaseIdFactory
    {
        #region Protected Members

        protected Gateway gateway;
        protected string tableName;
        protected string columnName;

        #endregion

        #region Constructors

        protected BaseIdFactory(string tableName, string columnName) : this(null, tableName, columnName)
        {
        }

        protected BaseIdFactory(Gateway gateway, string tableName, string columnName)
        {
            this.gateway = gateway;

            if (this.gateway == null)
            {
                gateway = Gateway.Default;
            }

            this.tableName = tableName;
            this.columnName = columnName;
        }

        #endregion
    }

    public class IdFactoryInt16 : BaseIdFactory
    {
        #region Private Members

        private short nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryInt16(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryInt16(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public short GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (short)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

    public class IdFactoryInt32 : BaseIdFactory
    {
        #region Private Members

        private int nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryInt32(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryInt32(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public int GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (int)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

    public class IdFactoryInt64 : BaseIdFactory
    {
        #region Private Members

        private long nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryInt64(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryInt64(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public long GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (long)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

    public class IdFactoryDouble : BaseIdFactory
    {
        #region Private Members

        private double nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryDouble(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryDouble(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public double GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (double)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

    public class IdFactoryFloat : BaseIdFactory
    {
        #region Private Members

        private float nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryFloat(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryFloat(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public float GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (float)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

    public class IdFactoryDecimal : BaseIdFactory
    {
        #region Private Members

        private decimal nextId = 0;
        private object syncObj = new object();

        #endregion

        #region Constructors

        public IdFactoryDecimal(string tableName, string columnName)
            : base(tableName, columnName)
        {
        }

        public IdFactoryDecimal(Gateway gateway, string tableName, string columnName)
            : base(gateway, tableName, columnName)
        {
        }

        #endregion

        #region Public Members

        public decimal GetNextId()
        {
            lock (syncObj)
            {
                if (nextId == 0)
                {
                    System.Data.DataSet ds = gateway.SelectDataSet(string.Format("select {0} from {1}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);

                    if (ds.Tables[0].Rows.Count == 0)
                    {
                        gateway.ExecuteNonQuery(string.Format("insert into {1} ({0}) values (1)", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName)), null);
                        nextId = 1;
                    }
                    else
                    {
                        nextId = (decimal)ds.Tables[0].Rows[0][0];
                    }
                }

                gateway.ExecuteNonQuery(string.Format("update {1} set {0} = {2}", gateway.BuildDbColumnName(columnName), gateway.BuildDbColumnName(tableName), gateway.BuildDbParamName(columnName)), new object[] { nextId + 1 });
            }

            return nextId++;
        }

        #endregion
    }

}
